﻿using System;

namespace SortMyPictures
{
    internal class RemainingTime
    {
        private int _kbSecAvg;
        private int _kbSecAvgHolding;
        private long _processedKB;

        private long _samples; // Number of samples comprising the Avg KB Sec
        private DateTime _startedAt;
        private long _totalKB;

        /// <summary>
        /// Initializes a new instance of the <see cref="RemainingTime"/> class.
        /// </summary>
        /// <param name="totalKB">The total KB.</param>
        internal RemainingTime(long totalKB)
        {
            _totalKB = totalKB;
            _startedAt = DateTime.Now;
        }

        internal event PercentCompleteChangedDelegate PercentCompleteChanged;

        /// <summary>
        /// Processeds the file.
        /// </summary>
        /// <param name="fileKB">The file KB.</param>
        internal void ProcessedFile(long fileKB)
        {
            _processedKB += fileKB;
            CalculateRemaining();
            CalculateKBSecAvg();
        }

        #region Helper Methods

        #region CalculateKBSecAvg

        /// <summary>
        /// Calculates the KB sec avg.
        /// </summary>
        private void CalculateKBSecAvg()
        {
            _samples++;
            if (_secondsToPercentage > 0)
            {
                double dkbSec = _processedKB/_secondsToPercentage;
                _kbSecAvgHolding += (int) dkbSec;
                _kbSecAvg = (int) (_kbSecAvgHolding/_samples);
            }
        }

        #endregion CalculateKBSecAvg

        #region CalculateRemaining

        /// <summary>
        /// Calculates the remaining.
        /// </summary>
        private void CalculateRemaining()
        {
            double pc = ((double) _processedKB/(double) _totalKB)*100;

            if (_percentageComplete != pc)
            {
                _percentageComplete = pc;
                if (null != PercentCompleteChanged)
                {
                    PercentCompleteChanged(_percentageComplete);
                }
                CalculateSecondsToPercentage();
                CalculateKBPerSecond();
                CalculateTimeRemaining();
            }
        }

        #endregion CalculateRemaining

        #region CalculateTimeRemaining

        /// <summary>
        /// Calculates the time remaining.
        /// </summary>
        private void CalculateTimeRemaining()
        {
            if (_kbSec != 0)
            {
                long remaining = _totalKB - _processedKB;
                int secondsToComplete = (int) (remaining/_kbSec);
                _timeRemaining = new TimeSpan(0, 0, 0, secondsToComplete);
            }
        }

        #endregion CalculateTimeRemaining

        #region CalculateKBPerSecond

        /// <summary>
        /// Calculates the KB per second.
        /// </summary>
        private void CalculateKBPerSecond()
        {
            if (_secondsToPercentage > 0)
            {
                double dkbSec = _processedKB/_secondsToPercentage;
                _kbSec = (int) dkbSec;
            }
        }

        #endregion CalculateKBPerSecond

        #region CalculateSecondsToPercentage

        /// <summary>
        /// Calculates the seconds elapsed to the current percentage.
        /// </summary>
        private void CalculateSecondsToPercentage()
        {
            TimeSpan ts = DateTime.Now.Subtract(_startedAt);
            _secondsToPercentage = (int) ts.TotalSeconds;
        }

        #endregion CalculateSecondsToPercentage

        #endregion Helper Methods

        #region Properties

        #region SecondsToPercentage

        private int _secondsToPercentage;

        /// <summary>
        /// Gets the seconds to percentage.
        /// </summary>
        /// <value>The seconds to percentage.</value>
        internal int SecondsToPercentage
        {
            get { return _secondsToPercentage; }
        }

        #endregion SecondsToPercentage

        #region KBSec

        private int _kbSec;

        /// <summary>
        /// Gets the KB sec.
        /// </summary>
        /// <value>The KB sec.</value>
        internal int KBSec
        {
            get { return _kbSec; }
        }

        #endregion KBSec

        #region PercentageComplete

        private double _percentageComplete = 0;

        /// <summary>
        /// Gets the percentage complete.
        /// </summary>
        /// <value>The percentage complete.</value>
        internal double PercentageComplete
        {
            get { return _percentageComplete; }
        }

        #endregion PercentageComplete

        #region TimeRemaining

        private TimeSpan _timeRemaining;

        /// <summary>
        /// Gets the time remaining.
        /// </summary>
        /// <value>The time remaining.</value>
        internal TimeSpan TimeRemaining
        {
            get { return _timeRemaining; }
        }

        #endregion TimeRemaining

        #region KBSecAvg

        /// <summary>
        /// Gets the KB sec avg.
        /// </summary>
        /// <value>The KB sec avg.</value>
        internal int KBSecAvg
        {
            get { return _kbSecAvg; }
        }

        #endregion KBSecAvg

        #endregion Properties

        #region Nested type: PercentCompleteChangedDelegate

        internal delegate void PercentCompleteChangedDelegate(double percentComplete);

        #endregion
    }
}